﻿using GTMC.Enum;
using GTMC.Interface.Communi;
using GTMC.Model;
using Leeder.GTMC.Communi;
using Leeder.Util;
using Leeder.Logger;
using LeederSerialPort;
using LogisticsAndong.Business;
using LogisticsAndong.Comm;
using LogisticsAndong.Enum;
using LogisticsAndong.Model;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace LogisticsAndong.Handle
{
    public class LogisticsAndongHandler
    {
        /// <summary>
        /// 日志
        /// </summary>
        public LogOperate LogObj => Log.GetLogger(this.GetType());
        /// <summary>
        /// 主要设备监控线程
        /// </summary>
        public CancellationTokenSource cancel_mainequip;
        /// <summary>
        /// 
        /// </summary>
        public CancellationTokenSource cancel_picsQueue;
        /// <summary>
        /// 丰田工机数据读取线程
        /// </summary>
        public CancellationTokenSource cancel_toyopucRead;
        /// <summary>
        /// 丰田工机状态监控线程
        /// </summary>
        public CancellationTokenSource cancel_TriaState;

        private MaterialDirectionBLL bllMaterialDirection = new MaterialDirectionBLL();
        private SystemDeviceMonitorBLL bllSystemDeviceMonitor = new SystemDeviceMonitorBLL();
        private TriaConnectBLL triaConnectBLL = new TriaConnectBLL();
        private TriaGroupBLL triaGroupBLL = new TriaGroupBLL();
        private TriaItemBLL triaItemBLL = new TriaItemBLL();
        private SignalLampMappingBLL signalLampMappingBLL = new SignalLampMappingBLL();
        private PlanMonitorBLL bllLogisticsSystemPlanMonitor = new PlanMonitorBLL();
        private UnpackingDirectionBLL unpackingDirectionBLL = new UnpackingDirectionBLL();

        /// <summary>
        /// 定义ups服务变量
        /// </summary>
        private UpsHandle upsServer;
        /// <summary>
        /// 顺引顺建剩余数量扣减事件
        /// </summary>
        public event Action LipChangeEvent;
        /// <summary>
        /// 拉绳灯状态变化事件
        /// </summary>
        public event Action LsdChangeEvent;

        AutoResetEvent atresetEvent = new AutoResetEvent(false);

        private ConcurrentQueue<WriteStruct> waittingQueue = new ConcurrentQueue<WriteStruct>();
        private class WriteStruct
        {
            public IToyopuc Toyopuc;
            public ProgramCode Code;
            public IndirectAddress Address;
            public List<byte> Val;
        }

        private LogisticsAndongHandler() { }
        private static LogisticsAndongHandler _LogisticsAndongBusiness = null;
        public static LogisticsAndongHandler CreateInstance()
        {
            if (_LogisticsAndongBusiness == null)
            {
                _LogisticsAndongBusiness = new LogisticsAndongHandler();
            }
            return _LogisticsAndongBusiness;
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public void Init()
        {
            InitData();
            InitToyopuc();
            InitTask();
            ToyopucMonitor();
            BlinkThead();
        }

        /// <summary>
        /// 初始化数据
        /// </summary>
        private void InitData()
        {
            LogObj.Info("初始化系统参数");

            SignalLampDirectionBLL bllSignalLampDirection = new SignalLampDirectionBLL();
            UnpackingDirectionBLL bllUnpackingDirection = new UnpackingDirectionBLL();
            SystemDeviceBLL bllSystemDevice = new SystemDeviceBLL();
            CarModelBLL bllCarModel = new CarModelBLL();

            //从数据库中取出系统需要的数据
            List<MaterialDirectionModel> materialDirectionList = bllMaterialDirection.GetModelList();
            List<SignalLampDirectionModel> signalLampDirectionList = bllSignalLampDirection.GetModelList();
            List<UnpackingDirectionModel> unpackingDirectionList = bllUnpackingDirection.GetModelList();
            List<SystemDeviceModel> systemDeviceList = bllSystemDevice.GetModelList();
            //carModelList = bllCarModel.GetModelList();

            //初始化全局变量
            GolbalVariable.PicsQueue = new ConcurrentQueue<PicsQueueModel>();
            GolbalVariable.SignalLampMappingList = signalLampMappingBLL.GetModelAll();
            GolbalVariable.MaterialDirectionBag = new ConcurrentBag<MaterialDirectionModel>(materialDirectionList);
            GolbalVariable.SignalLampDirectionBag = new ConcurrentBag<SignalLampDirectionModel>(signalLampDirectionList);
            GolbalVariable.SignalLampDirectionBag.ForEach(x => { x.Status = 0; });//初始化全部信号灯状态为0
            GolbalVariable.UnpackingDirectionBag = new ConcurrentBag<UnpackingDirectionModel>(unpackingDirectionList);
            GolbalVariable.SystemDeviceBag = new ConcurrentBag<SystemDeviceModel>(systemDeviceList);
            GolbalVariable.SignalLampBlinkThreadDictionary = new ConcurrentDictionary<string, Thread>();
            GolbalVariable.SignalLampShowModelBag = new ConcurrentBag<SignalLampShowModel>();
            GolbalVariable.UnpackingDirectionModelBag = new ConcurrentBag<UnpackingDirectionShowModel>();
            GolbalVariable.CurrentParamet = new CurrentParameter();
            GolbalVariable.UpsStatus = new UpsModel();
            GolbalVariable.LipState = true;
            GolbalVariable.PlcState = true;

            CurrentParameter currentParamet = new CurrentParameter();
            GolbalVariable.CurrentParamet = currentParamet;

            //初始化全局变量
            foreach (var signalLamp in signalLampDirectionList)
            {
                var unpacking = unpackingDirectionList.Where(p => p.ID == signalLamp.UnpackingId).FirstOrDefault();
                var signalLampAddress = GolbalVariable.SignalLampMappingList.Where(s => s.ID == signalLamp.SignalLampMappingID).FirstOrDefault();
                if (unpacking != null)
                {
                    SignalLampShowModel model = new SignalLampShowModel
                    {
                        Id = signalLamp.ID,
                        LampId = signalLamp.ID,
                        PullingRopeName = signalLamp.LampName,
                        ChainMark = signalLamp.ChainMark,
                        PullingRopeInAddress = signalLampAddress.ControlInputAddress,
                        GreenOutAddress = signalLampAddress.GreenOutputAddress,
                        RedOutAddress = signalLampAddress.RedOutputAddress,
                        TypeId = signalLamp.TypeId
                    };
                    GolbalVariable.SignalLampShowModelBag.Add(model);
                }
            }

            //初始化全局变量
            foreach (var unpacking in unpackingDirectionList)
            {
                UnpackingDirectionShowModel model = new UnpackingDirectionShowModel
                {
                    Id = unpacking.ID,
                    UnpackingId = unpacking.ID,
                    UnpackingName = unpacking.UnpackingName,
                    DataType = unpacking.DataType,
                    IpAddress = unpacking.IpAddress,
                    SignalMark = unpacking.SignalMark,
                    ControlName = unpacking.ControlName,
                    TypeId = unpacking.TypeId
                };
                GolbalVariable.UnpackingDirectionModelBag.Add(model);
            }
            LogObj.Info("系统参数初始化完成");
        }

        /// <summary>
        /// 初始化丰田工机
        /// </summary>
        public void InitToyopuc()
        {
            LogObj.Info("初始化丰田工机");
            try
            {
                GolbalVariable.TriaConnectList = triaConnectBLL.GetModelList();
                GolbalVariable.TriaGroupList = triaGroupBLL.GetModelList();
                GolbalVariable.TriaItemList = triaItemBLL.GetModelList();
                GolbalVariable.PlcTriaList = new List<TriaModel>();
                foreach (var conn in GolbalVariable.TriaConnectList)
                {
                    TriaModel triaModel = new TriaModel();
                    GolbalVariable.PlcTriaList.Add(triaModel);
                    //IToyopuc ToyopucHandler = ToyopucInstance.GetInstance("192.168.100.120", 2005);
                    triaModel.ToyopucHandler = ToyopucInstance.GetInstance(conn.Ip, conn.Port);
                    triaModel.Ip = conn.Ip;
                    triaModel.Port = conn.Port;
                    triaModel.AccessMode = conn.AccessMode;
                    triaModel.ProgramCode = (ProgramCode)conn.ProgramCode;
                    triaModel.TriaAddress = new IndirectAddress();
                    triaModel.TriaAddress.Identifier = conn.Identifier;
                    triaModel.TriaAddress.Address = (uint)conn.Address;
                    triaModel.AddressLength = (short)conn.AddressLength;
                    triaModel.TriaGroups = new List<TriaGroup>();
                    for (uint i = triaModel.TriaAddress.Address; i < (triaModel.TriaAddress.Address + triaModel.AddressLength); i++)
                    {
                        var groupId = triaModel.TriaAddress.Identifier + i.ToString("X");
                        var group = GolbalVariable.TriaGroupList.Where(s => s.GroupAddress == groupId && s.TriaConnectID == conn.ID).FirstOrDefault();
                        if (group == null)
                            continue;
                        TriaGroup triaGroup = new TriaGroup
                        {
                            GroupId = groupId,
                            GroupDataType = group.GroupType == 0 ? TriaDataType.Booleans : TriaDataType.Integer,
                            Value = -1,
                            LastValue = -1,
                            Items = new List<TriaItem>()
                        };
                        triaModel.TriaGroups.Add(triaGroup);
                        switch (triaGroup.GroupDataType)
                        {
                            case TriaDataType.Integer:
                                triaGroup.Items.Add(new TriaItem
                                {
                                    ItemId = triaGroup.GroupId + "_0"
                                });
                                break;
                            case TriaDataType.Booleans:
                                for (int j = 0; j < 16; j++)
                                {
                                    triaGroup.Items.Add(new TriaItem
                                    {
                                        ItemId = triaGroup.GroupId + "_" + j.ToString("X")
                                    });
                                }
                                break;
                        }
                    }

                }
                LogObj.Info("丰田工机初始化完成");
            }
            catch (Exception ex)
            {
                LogObj.Error("丰田工机初始化失败：" + ex.Message);
            }
        }

        /// <summary>
        /// 初始化线程
        /// </summary>
        private void InitTask()
        {
            //主要设备监控线程
            if (GolbalVariable.SystemDeviceBag.Where(x => x.DataSource == "IP").Any())
            {
                cancel_mainequip = new CancellationTokenSource();
                LogObj.Info("开启主要设备监控线程启动");
                Task.Factory.StartNew(() =>
                {
                    BindMainPower();
                }, cancel_mainequip.Token);
            }
            //丰田工机数据监控线程(读取数据，判断是否有按钮按下)
            cancel_toyopucRead = new CancellationTokenSource();
            LogObj.Info("丰田工机信号监控线程启动");
            Task.Factory.StartNew(() =>
            {
                ToyopucRead();
            }, cancel_toyopucRead.Token);

            //开启PICS数据处理工作线程
            cancel_picsQueue = new CancellationTokenSource();
            LogObj.Info("PICS数据处理线程启动");
            Task.Factory.StartNew(() =>
            {
                PicsQueue();
            }, cancel_picsQueue.Token);

            //创建ups监控对象的实例
            upsServer = new UpsHandle();
            //接收数据事件
            upsServer.Received += UpsServer_Received;
            //初始化com口
            LogObj.Info("ups监控线程开启");
            upsServer.InitCom();
            Wrtite();
        }

        private bool plcStatus = true;
        private bool lipStatus = true;
        /// <summary>
        /// 绑定硬件设备
        /// </summary>
        private async void BindMainPower()
        {
            string plcIp = GolbalVariable.SystemDeviceBag.Where(x => x.DataSource == "IP" && x.DeviceName == "PLC").FirstOrDefault().DeviceIpAddress;
            string lipIp = GolbalVariable.SystemDeviceBag.Where(x => x.DataSource == "IP" && x.DeviceName == "LIP").FirstOrDefault().DeviceIpAddress;
            while (true)
            {
                if (cancel_mainequip.Token.IsCancellationRequested)
                {
                    cancel_mainequip.Dispose();
                    break;
                }
                plcStatus = PublicHelper.PingIp(plcIp);
                lipStatus = PublicHelper.PingIp(lipIp);
                if (!plcStatus && GolbalVariable.PlcState != false)
                {
                    SystemDeviceMonitorModel model = new SystemDeviceMonitorModel()
                    {
                        ID = GolbalVariable.SystemDeviceBag.Where(x => x.DataSource == "IP" && x.DeviceName == "PLC").FirstOrDefault().ID,
                        DeviceName = GolbalVariable.SystemDeviceBag.Where(x => x.DataSource == "IP" && x.DeviceName == "PLC").FirstOrDefault().DeviceName,
                        ExceptionDescription = "设备通讯异常",
                        ExceptionDate = DateTime.Now
                    };
                    bllSystemDeviceMonitor.Add(model);
                    GolbalVariable.PlcState = false;
                }
                else
                { GolbalVariable.PlcState = plcStatus; }
                if (!lipStatus && GolbalVariable.LipState != false)
                {
                    SystemDeviceMonitorModel model = new SystemDeviceMonitorModel()
                    {
                        ID = GolbalVariable.SystemDeviceBag.Where(x => x.DataSource == "IP" && x.DeviceName == "LIP").FirstOrDefault().ID,
                        DeviceName = GolbalVariable.SystemDeviceBag.Where(x => x.DataSource == "IP" && x.DeviceName == "LIP").FirstOrDefault().DeviceName,
                        ExceptionDescription = "设备通讯异常",
                        ExceptionDate = DateTime.Now
                    };
                    bllSystemDeviceMonitor.Add(model);
                    GolbalVariable.LipState = false;
                }
                else
                { GolbalVariable.LipState = lipStatus; }
                await Task.Delay(5000);
            }
        }

        /// <summary>
        /// 丰田工机通讯监控
        /// </summary>
        public void ToyopucMonitor()
        {
            Thread thread = new Thread(() =>
            {
                while (true)
                {
                    bool re = atresetEvent.WaitOne(60000);//等60秒，60秒没有信号则取消旧线程重新创建读取线程
                    if (re)
                    {

                    }
                    else
                    {
                        LogObj.Error("丰田工机通讯异常，无法读取数据！");
                        //丰田工机数据监控线程(读取数据，判断是否有按钮按下)
                        cancel_toyopucRead.Cancel();
                        Thread.Sleep(300);
                        cancel_toyopucRead = new CancellationTokenSource();
                        Task.Factory.StartNew(() =>
                        {
                            InitToyopuc();
                            ToyopucRead();
                        }, cancel_toyopucRead.Token);
                    }
                }
            }
            );
            thread.IsBackground = true;
            thread.Start();
        }

        /// <summary>
        /// 实时读取丰田Toyopuc数据
        /// </summary>
        private async void ToyopucRead()
        {
            while (!this.cancel_toyopucRead.Token.IsCancellationRequested)
            {
                //遍历所有连接
                foreach (var plcTria in GolbalVariable.PlcTriaList)
                {
                    await Task.Delay(20);
                    //如果连接
                    if (plcTria.AccessMode == "writeOnly")
                        continue;
                    var toyopucHandler = plcTria.ToyopucHandler;
                    if (toyopucHandler == null) continue;
                    byte[] result = null;
                    try
                    {
                        //查询当前按钮的状态
                        result = toyopucHandler.ReadExtString(plcTria.ProgramCode, plcTria.TriaAddress, plcTria.AddressLength);
                        if (result.Length > 0)
                            atresetEvent.Set();
                    }
                    catch (Exception ex)
                    {
                        LogObj.Error("PLC数据读取异常:" + ex.Message);
                        continue;
                    }
                    //将读到的字节转换成二进制字符串
                    string resultStr = PublicHelper.ByteToStr(result);
                    //比较当前读到数据是否与上一次记录数据一样，一样则不做处理，不一样则进行下一步处理
                    if (plcTria.DataStr != resultStr)
                    {
                        plcTria.DataByte = result;
                        plcTria.DataStr = resultStr;
                        int packetIndex = 0;
                        //循环判断每一组数据
                        for (uint i = plcTria.TriaAddress.Address; i < (plcTria.TriaAddress.Address + plcTria.AddressLength); i++)
                        {
                            try
                            {
                                //根据组ID获取该组
                                var triaGroup = plcTria.TriaGroups.Where(s => s.GroupId == plcTria.TriaAddress.Identifier + i.ToString("X")).FirstOrDefault();
                                if (triaGroup == null)
                                {
                                    var states = resultStr.FindIndexString(ref packetIndex, 16);
                                    continue;
                                }
                                //截取该组数据(转换后的二进制字符串)
                                var groupStates = resultStr.FindIndexString(ref packetIndex, 16);

                                //比较该组当前读到数据是否与上一次记录数据一样，一样则不做处理，不一样则进行下一步处理
                                if (triaGroup.GroupStrs != groupStates)
                                {
                                    triaGroup.LastValue = triaGroup.Value;
                                    triaGroup.Value = BitConverter.ToUInt16(result, (int)((i - plcTria.TriaAddress.Address) * 2));
                                    triaGroup.GroupStrs = groupStates;
                                    var group = GolbalVariable.TriaGroupList.Where(s => s.GroupAddress == plcTria.TriaAddress.Identifier + i.ToString("X")).FirstOrDefault();
                                    var items = GolbalVariable.TriaItemList.Where(s => s.GroupID == group.ID).ToList();
                                    LogObj.Info("Group信号触发(" + group.GroupAddress + "):" + triaGroup.Value + "(" + groupStates + ")");

                                    //根据组名分别调用不同的逻辑方法
                                    switch (triaGroup.GroupDataType)
                                    {
                                        case TriaDataType.Integer:
                                            //比较当前项读到数据是否与上一次记录数据一样，一样则不做处理，不一样则进行下一步处理          
                                            if (triaGroup.Items[0].Value == null || (triaGroup.Items[0].Value != triaGroup.Value))
                                            {
                                                //将读到的二进制数转成十进制数并更新到数据模型中
                                                triaGroup.Items[0].Value = triaGroup.Value;
                                                LogObj.Info("Item(Word)信号触发(" + group.GroupAddress + "):" + triaGroup.Items[0].Value + "(" + triaGroup.GroupStrs + ")");
                                                //根据组名分别调用不同的逻辑方法
                                                switch (group.SignalMark)
                                                {
                                                    case "LIP":
                                                        if (triaGroup.LastValue.ToInt() != -1 && triaGroup.Value.ToInt() != 0)
                                                        {
                                                            for (int k = 0; k < ((triaGroup.Value.ToInt() - triaGroup.LastValue.ToInt())); k++)
                                                            {
                                                                LipGroup(items[0].SignalMark, 1);
                                                                await Task.Delay(10);
                                                            }
                                                        }
                                                        break;
                                                    case "LSD":
                                                        break;
                                                    case "KK":
                                                        break;
                                                    case "RD":
                                                        RdGroup(items[0].SignalMark, Convert.ToInt32(triaGroup.Items[0].Value));
                                                        break;
                                                    case "SBJK":
                                                        break;
                                                    case "PICS":
                                                        //业务处理
                                                        GolbalVariable.PicsQueue.Enqueue(new PicsQueueModel { SignalMark = items[0].SignalMark, Result = Convert.ToInt32(triaGroup.Items[0].Value) });
                                                        //PicsGroup(items[0].SignalMark, Convert.ToInt32(triaGroup.Items[0].Value));
                                                        break;
                                                    case "LSZT":
                                                        break;
                                                }
                                            }
                                            break;
                                        case TriaDataType.Booleans:
                                            for (int j = 0; j < 16; j++)
                                            {
                                                //比较当前项读到数据是否与上一次记录数据一样，一样则不做处理，不一样则进行下一步处理
                                                if (triaGroup.Items[j].Value == null || (triaGroup.Items[j].Value.ToInt() != int.Parse(groupStates[j].ToString())))
                                                {
                                                    var val = triaGroup.Items[j].Value;
                                                    LogObj.Info("Item(Bit)信号触发(" + group.GroupAddress + "_" + j + "):" + val + "(" + triaGroup.Items[j].Value.ToInt() + ")");
                                                    var item = items.Where(s => s.ItemAddress == triaGroup.Items[j].ItemId).FirstOrDefault();
                                                    //将读到的二进制数转成单个0或1并更新到数据模型中
                                                    triaGroup.Items[j].Value = int.Parse(groupStates[j].ToString());
                                                    //根据组名分别调用不同的逻辑方法
                                                    switch (group.SignalMark)
                                                    {
                                                        case "LIP":
                                                            LipGroup(items[j].SignalMark, triaGroup.Items[j].Value.ToInt());
                                                            break;
                                                        case "LSD":
                                                            break;
                                                        case "KK":
                                                            break;
                                                        case "RD":
                                                            break;
                                                        case "SBSD":
                                                            SbsdGroup(items[j].SignalMark, triaGroup.Items[j].Value.ToInt());
                                                            break;
                                                        case "SBTX":
                                                            SbjkGroup(items[j].SignalMark, triaGroup.Items[j].Value.ToInt());
                                                            break;
                                                        case "PICS":
                                                            break;
                                                        case "LSZT":
                                                            LsztGroup(items[j].SignalMark, triaGroup.Items[j].Value.ToInt());
                                                            break;
                                                        case "TS":
                                                            if (val != null)
                                                                LipGroup(items[j].SignalMark, triaGroup.Items[j].Value.ToInt());
                                                            break;
                                                    }
                                                }
                                            }
                                            break;
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                LogObj.Error(ex.Message);
                                break;
                            }
                        }
                    }
                }
                //休眠
                await Task.Delay(100);
            }
        }

        /// <summary>
        /// UPS接收数据事件
        /// </summary>
        /// <param name="data"></param>
        private void UpsServer_Received(UpsModel data)
        {
            //把UPS当前状态更新到缓存中（用于界面状态的更新）
            GolbalVariable.UpsStatus = data;
            //数据处理
            UpsBusiness.CheckUps(data);
        }

        /// <summary>
        /// LIP处理逻辑
        /// 物料数量扣减和重置，信号为NO时对应物料数量减1，等于0时重置数量
        /// </summary>
        public void LipGroup(string signalMark, int result)
        {
            if (result == 0)
                return;
            //把OPC触发点对应的部品装进队列里，以供另外一个线程读取并做相应的运算
            var plans = GolbalVariable.MaterialDirectionBag.Where(x => x.SignalMark == signalMark).ToList();
            if (plans != null)
                plans.ForEach(x =>
                {
                    //计算方法
                    int left_count = x.LeftCount;
                    CalculationHelper.Subtraction(ref left_count, 1);
                    //如果剩余台数小于1，则剩余台数等于工程台数,开始新的一轮循环
                    var res = CalculationHelper.CustomOperation(ref left_count, 3, 1, x.ProjectCount);
                    //如果部品开始新的一轮循环且部品类型为内制品则出发工程数减1
                    if (res && x.TypeId == 4)
                    {
                        int project_count = x.TransportProjectCount;
                        CalculationHelper.Subtraction(ref project_count, 1);
                        CalculationHelper.CustomOperation(ref project_count, 3, 1, x.TriggerProjectCount);
                        x.TransportProjectCount = project_count;
                    }
                    x.LeftCount = left_count;
                    //把运算后的部品实体更新到数据库
                    bllMaterialDirection.Update(x);
                    LipChangeEvent?.BeginInvoke(null, null);
                    LogObj.Info("顺引顺建/内制品/排序工程剩余台数扣减(" + x.MaterialName + ":" + x.LeftCount + ")");
                });
        }

        /// <summary>
        /// LSD处理逻辑
        /// 读取信号灯当前状态，更新缓存，然后同步更新软件界面显示
        /// </summary>
        public void LsdGroup(string signalMark, int result)
        {
            //判断触发点是否为绿灯
            var signalLampModels1 = GolbalVariable.SignalLampShowModelBag.Where(x => x.GreenOutAddress == signalMark).ToList();
            if (signalLampModels1 != null)
                signalLampModels1.ForEach(x =>
                {
                    //更新缓存中绿灯的状态
                    x.IsGreen = result;
                });
            //判断触发点是否为红灯
            var signalLampModels2 = GolbalVariable.SignalLampShowModelBag.Where(x => x.RedOutAddress == signalMark).ToList();
            if (signalLampModels2 != null)
                signalLampModels2.ForEach(x =>
                {
                    //更新缓存中红灯的状态
                    x.IsRed = result;
                });
            LsdChangeEvent?.BeginInvoke(null, null);
        }

        /// <summary>
        /// LSZT处理逻辑
        /// 通过拉绳信号完成对信号灯的状态控制
        /// 信号灯共有5种状态：0常态(绿灭红灭)；1提示配送(绿闪红灭)；2未在规定时间内配送(绿闪红亮)；3配送状态(绿亮红灭)；4未在规定时间内完成配送(绿亮红亮)；
        /// </summary>
        public void LsztGroup(string signalMark, int result)
        {
            if (result == 0)
                return;
            var signalLamp = GolbalVariable.SignalLampMappingList.Where(x => x.ControlInputAddress == signalMark).FirstOrDefault();
            //根据信号灯当前状态判断拉绳后的状态
            var signalLamps = GolbalVariable.SignalLampDirectionBag.Where(x => x.SignalLampMappingID == signalLamp.ID).ToList();
            signalLamps.ForEach(x =>
            {
                LogObj.Info("拉绳触发(" + x.LampName + ")，信号灯当前状态:" + GetState(x.Status));
                //查找出对应的开捆对象
                var unpacking = GolbalVariable.UnpackingDirectionModelBag.Where(u => u.UnpackingId == x.UnpackingId).FirstOrDefault();
                //查找出对应的红灯绿灯地址
                var infoR = GolbalVariable.TriaItemList.Where(p => p.SignalMark == signalLamp.RedOutputAddress).ToList();
                var infoG = GolbalVariable.TriaItemList.Where(p => p.SignalMark == signalLamp.GreenOutputAddress).ToList();
                switch (x.Status)
                {
                    case 0:
                        //0状态(常态)下拉绳不作处理
                        LogObj.Info("信号灯当前状态(" + x.LampName + "):" + GetState(x.Status));
                        //绿灯灭
                        infoG.ForEach(f =>
                    {
                        SignalLampControl(f.ItemAddress, 0);
                    });
                        //红灯灭
                        infoR.ForEach(f =>
                    {
                        SignalLampControl(f.ItemAddress, 0);
                    });
                        break;
                    case 1:
                        //1状态(提示配送)下拉绳信号灯变成3状态(配送状态)
                        x.Status = 3;
                        LogObj.Info("信号灯当前状态(" + x.LampName + "):" + GetState(x.Status));
                        //绿灯亮
                        infoG.ForEach(f =>
                    {
                        SignalLampControl(f.ItemAddress, 1);
                    });
                        //红灯灭
                        infoR.ForEach(f =>
                    {
                        SignalLampControl(f.ItemAddress, 0);
                    });

                        //记录出发延迟信息
                        PlanMonitorModel model = new PlanMonitorModel()
                        {
                            DelayState = 1,
                            ProductName = x.LampName,
                            AreaType = int.Parse(x.UnpackingId.ToString()),
                            AreaName = unpacking.UnpackingName,
                            Description = "正常作业",
                            StartTime = DateTime.Now,
                            EndTime = DateTime.Now,
                            WorkStartTime = DateTime.Now,
                            WorkEndTime = DateTime.Now,
                            CreateTime = DateTime.Now,
                        };
                        bllLogisticsSystemPlanMonitor.Add(model);

                        break;
                    case 2:
                        //2状态(未在规定时间内配送)下拉绳信号灯变成3状态(配送状态)
                        x.Status = 3;
                        LogObj.Info("信号灯当前状态(" + x.LampName + "):" + GetState(x.Status));
                        //绿灯亮
                        infoG.ForEach(f =>
                    {
                        SignalLampControl(f.ItemAddress, 1);
                    });
                        //红灯灭
                        infoR.ForEach(f =>
                    {
                        SignalLampControl(f.ItemAddress, 0);
                    });

                        //记录出发延迟信息
                        PlanMonitorModel model1 = new PlanMonitorModel()
                        {
                            DelayState = 3,
                            ProductName = x.LampName,
                            AreaType = int.Parse(x.UnpackingId.ToString()),
                            AreaName = unpacking.UnpackingName,
                            Description = "延迟拉绳",
                            StartTime = DateTime.Now,
                            EndTime = DateTime.Now,
                            WorkStartTime = DateTime.Now,
                            WorkEndTime = DateTime.Now,
                            CreateTime = DateTime.Now,
                        };
                        bllLogisticsSystemPlanMonitor.Add(model1);

                        break;
                    case 3:
                        //3状态(配送状态)下拉绳信号灯变成0状态(配送结束)
                        x.Status = 0;
                        LogObj.Info("信号灯当前状态(" + x.LampName + "):" + GetState(x.Status));
                        //绿灯灭
                        infoG.ForEach(f =>
                    {
                        SignalLampControl(f.ItemAddress, 0);
                    });
                        //红灯灭
                        infoR.ForEach(f =>
                    {
                        SignalLampControl(f.ItemAddress, 0);
                    });
                        break;
                    case 4:
                        //4状态(未在规定时间内完成配送)下拉绳信号灯变成0状态(配送结束)
                        x.Status = 0;
                        LogObj.Info("信号灯当前状态(" + x.LampName + "):" + GetState(x.Status));
                        //绿灯灭
                        infoG.ForEach(f =>
                    {
                        SignalLampControl(f.ItemAddress, 0);
                    });
                        //红灯灭
                        infoR.ForEach(f =>
                    {
                        SignalLampControl(f.ItemAddress, 0);
                    });
                        break;
                }
            });
        }

        public string GetState(int stateCode)
        {
            switch (stateCode)
            {
                case 0:
                    //0状态(常态)下拉绳不作处理
                    return "常态";
                    break;
                case 1:
                    //1状态(提示配送)下拉绳信号灯变成3状态(配送状态)
                    return "提示配送";
                    break;
                case 2:
                    //2状态(未在规定时间内配送)下拉绳信号灯变成3状态(配送状态)
                    return "未在规定时间内开始配送";
                    break;
                case 3:
                    //3状态(配送状态)下拉绳信号灯变成0状态(配送结束)
                    return "配送状态";
                    break;
                case 4:
                    //4状态(未在规定时间内完成配送)下拉绳信号灯变成0状态(配送结束)
                    return "未在规定时间内完成配送";
                    break;
                default:
                    return "未定义状态";
                    break;
            }
        }

        /// <summary>
        /// SBJK处理逻辑
        /// 监控硬件设备的状态并同步更新缓存，OFF为异常，NO为正常
        /// </summary>
        public void SbjkGroup(string signalMark, int result)
        {
            var systemDevices = GolbalVariable.SystemDeviceBag.Where(x => x.SignalMark == signalMark && x.Enabled).ToList();
            systemDevices.ForEach(x =>
            {
                //设备异常时把异常信息保存到数据库，触发前状态已经是异常的不做记录(连续异常只记录第一次)
                if (result == 0 && x.Status != result)
                {
                    LogObj.Error("设备通讯异常:" + x.DeviceName);
                    SystemDeviceMonitorModel model = new SystemDeviceMonitorModel()
                    {
                        DeviceId = x.ID.ToString(),
                        DeviceName = x.DeviceName,
                        ExceptionDescription = "设备通讯异常",
                        ExceptionDate = DateTime.Now
                    };
                    bllSystemDeviceMonitor.Add(model);
                }
                //更新设备缓存状态
                x.Status = result;
            });
        }


        public void SbsdGroup(string signalMark, int result)
        {
            if (result == 0)
                return;
            var systemDevices = GolbalVariable.SystemDeviceBag.Where(x => x.SignalMark == signalMark).ToList();
            systemDevices.ForEach(x =>
            {
                LogObj.Info("设备启用:" + x.DeviceName);
                x.Enabled = true;
            });
        }

        /// <summary>
        /// PLC RD组处理逻辑
        /// </summary>
        public void RdGroup(string signalMark, int result)
        {
            //链数/台数更新
            var unpackings = GolbalVariable.UnpackingDirectionModelBag.Where(x => x.SignalMark == signalMark).ToList();
            if (unpackings != null)
                foreach (UnpackingDirectionShowModel x in unpackings)
                {
                    x.UnpackingCount = result;
                    var model = unpackingDirectionBLL.GetById(x.Id).ActivedObj;
                    model.Amount = result;
                    unpackingDirectionBLL.Update(model);
                }
        }

        /// <summary>
        /// 将顺引顺建数据写入Opc
        /// </summary>
        private async void PicsQueue()
        {
            while (!this.cancel_picsQueue.Token.IsCancellationRequested)
            {

                if (!GolbalVariable.PicsQueue.IsEmpty)
                {
                    PicsQueueModel result;
                    GolbalVariable.PicsQueue.TryDequeue(out result);
                    if (result != null)
                    {
                        PicsGroup(result.SignalMark, result.Result);
                    }
                    await Task.Delay(20);
                }
                else
                {
                    await Task.Delay(100);
                }
            }
        }

        /// <summary>
        /// PICS处理逻辑
        /// </summary>
        public void PicsGroup(string signalMark, int result)
        {
            //链数/台数更新
            var unpackings = GolbalVariable.UnpackingDirectionModelBag.Where(x => x.SignalMark == signalMark).ToList();
            if (unpackings != null)
                foreach (UnpackingDirectionShowModel x in unpackings)
                {
                    x.UnpackingCount = result;

                    var UnpackModel = unpackingDirectionBLL.GetById(x.Id).ActivedObj;
                    UnpackModel.Amount = result;
                    unpackingDirectionBLL.Update(UnpackModel);
                    //查找是否绑定信号灯，并根据信号灯设置的参数及当前状态判断信号灯的下一步状态
                    var signalLamps = GolbalVariable.SignalLampDirectionBag.Where(s => s.UnpackingId == x.UnpackingId && s.Enable == 1).ToList();
                    foreach (var signalLamp in signalLamps)
                    {
                        if (signalLamp != null)
                        {
                            LogObj.Info("Pics触发(" + signalLamp.LampName + ")，当前台数:" + result + "，信号灯当前状态:" + GetState(signalLamp.Status));
                            var signalLampMapping = GolbalVariable.SignalLampMappingList.Where(k => k.ID == signalLamp.SignalLampMappingID).FirstOrDefault();
                            //查找出开捆台数对应的开捆链数对象，用于单双链判断
                            var unpacking = GolbalVariable.UnpackingDirectionModelBag.Where(u => u.UnpackingName == x.UnpackingName && u.DataType == "链数").FirstOrDefault();
                            //查找出对应的红灯绿灯地址
                            var infoR = GolbalVariable.TriaItemList.Where(p => p.SignalMark == signalLampMapping.RedOutputAddress).ToList();
                            var infoG = GolbalVariable.TriaItemList.Where(p => p.SignalMark == signalLampMapping.GreenOutputAddress).ToList();

                            //单双链逻辑判断(0全部，1单数，2双数)
                            if (signalLamp.ChainMark == "1")
                            {
                                //单数链触发
                                //当前链数为双数时不触发
                                if (!Convert.ToBoolean(unpacking.UnpackingCount % 2))
                                {
                                    //返回不做处理
                                    continue;
                                }
                            }
                            else if (signalLamp.ChainMark == "2")
                            {
                                //双数链触发
                                //当前链数为单数时不触发
                                if (Convert.ToBoolean(unpacking.UnpackingCount % 2))
                                {
                                    //返回不做处理
                                    continue;
                                }
                            }
                            //当前台数等于出发台数时触发(提示开始配送)
                            if (signalLamp.TriggerCount == result)
                            {
                                switch (signalLamp.Status)
                                {
                                    case 0:
                                        //0状态(常态)下变成提示配送(1状态)
                                        signalLamp.Status = 1;
                                        //绿灯闪
                                        infoG.ForEach(f =>
                                        {
                                            StartBlink(f.ItemAddress);
                                        });
                                        //红灯灭
                                        infoR.ForEach(f =>
                                        {
                                            SignalLampControl(f.ItemAddress, 0);
                                        });
                                        LogObj.Info("信号灯当前状态(" + signalLamp.LampName + "):" + GetState(signalLamp.Status));
                                        break;
                                    case 1:
                                        //1状态(提示配送)下不做处理
                                        break;
                                    case 2:
                                        //2状态(未在规定时间内配送)下不做处理
                                        break;
                                    case 3:
                                        //3状态(配送状态)下不做处理
                                        break;
                                    case 4:
                                        //4状态(未在规定时间内完成配送)下不做处理
                                        break;
                                }
                            }
                            //当前台数等于延迟出发台数时触发(提示配送延迟)
                            else if (signalLamp.TriggerDelayCount == result)
                            {
                                switch (signalLamp.Status)
                                {
                                    case 0:
                                        //0状态(常态)下不做处理
                                        break;
                                    case 1:
                                        //1状态(提示配送)下变成未在规定时间内配送(2状态)
                                        signalLamp.Status = 2;
                                        //绿灯闪
                                        infoG.ForEach(f =>
                                        {
                                            StartBlink(f.ItemAddress);
                                        });
                                        //红灯亮
                                        infoR.ForEach(f =>
                                        {
                                            SignalLampControl(f.ItemAddress, 1);
                                        });

                                        //记录出发延迟信息
                                        PlanMonitorModel model1 = new PlanMonitorModel()
                                        {
                                            DelayState = 2,
                                            ProductName = signalLamp.LampName,
                                            AreaType = int.Parse(x.UnpackingId.ToString()),
                                            AreaName = x.UnpackingName,
                                            Description = "出发延迟",
                                            StartTime = DateTime.Now,
                                            EndTime = DateTime.Now,
                                            WorkStartTime = DateTime.Now,
                                            WorkEndTime = DateTime.Now,
                                            CreateTime = DateTime.Now,
                                        };
                                        bllLogisticsSystemPlanMonitor.Add(model1);
                                        LogObj.Info("信号灯当前状态(" + signalLamp.LampName + "):" + GetState(signalLamp.Status));
                                        break;
                                    case 2:
                                        //2状态(未在规定时间内配送)下不做处理
                                        //signalLamp.status = 3;
                                        break;
                                    case 3:
                                        //3状态(配送状态)下不做处理
                                        //signalLamp.status = 0;
                                        break;
                                    case 4:
                                        //4状态(未在规定时间内完成配送)下不做处理
                                        //signalLamp.status = 0;
                                        break;
                                }
                            }
                            //当前台数等于结束延迟台数时触发(提示配送结束延迟)
                            else if (signalLamp.EndDelayCount == result)
                            {
                                switch (signalLamp.Status)
                                {
                                    case 0:
                                        //0状态(常态)下不做处理
                                        //signalLamp.status = 4;
                                        break;
                                    case 1:
                                        //1状态(提示配送)下不做处理
                                        //signalLamp.status = 3;
                                        break;
                                    case 2:
                                        //2状态(未在规定时间内配送)下不做处理
                                        //signalLamp.status = 3;
                                        break;
                                    case 3:
                                        //3状态(配送状态)下变成未在规定时间内完成配送(4状态)
                                        signalLamp.Status = 4;
                                        //绿灯亮
                                        infoG.ForEach(f =>
                                        {
                                            SignalLampControl(f.ItemAddress, 1);
                                        });
                                        //红灯亮
                                        infoR.ForEach(f =>
                                        {
                                            SignalLampControl(f.ItemAddress, 1);
                                        });

                                        //记录出发延迟信息
                                        PlanMonitorModel model = new PlanMonitorModel()
                                        {
                                            DelayState = 4,
                                            ProductName = signalLamp.LampName,
                                            AreaType = int.Parse(x.UnpackingId.ToString()),
                                            AreaName = x.UnpackingName,
                                            Description = "结束延迟",
                                            StartTime = DateTime.Now,
                                            EndTime = DateTime.Now,
                                            WorkStartTime = DateTime.Now,
                                            WorkEndTime = DateTime.Now,
                                            CreateTime = DateTime.Now,
                                        };
                                        bllLogisticsSystemPlanMonitor.Add(model);
                                        LogObj.Info("信号灯当前状态(" + signalLamp.LampName + "):" + GetState(signalLamp.Status));
                                        break;
                                    case 4:
                                        //4状态(未在规定时间内完成配送)下不做处理
                                        break;
                                }
                            }
                        }
                    }
                }
        }

        /// <summary>
        /// 重置拉绳灯(新)
        /// </summary>
        public void ResetSignalLamp()
        {
            System.Threading.Tasks.Task.Run(async delegate
            {
                SignalLampStateBag.ForEach(f =>
                {
                    f.IsBlink = false;
                    Thread.Sleep(5);
                });

                Thread.Sleep(500);

                var lsds = GolbalVariable.TriaGroupList.Where(x => x.SignalMark == "LSD").ToList();
                foreach (var lsd in lsds)
                {
                    //将数据更新至PLC
                    foreach (var plcTria in GolbalVariable.PlcTriaList)
                    {
                        var address = Convert.ToInt32(lsd.GroupAddress.Substring(1, lsd.GroupAddress.Length - 1), 16);
                        var groups = plcTria.TriaGroups.Where(s => s.GroupId == lsd.GroupAddress).ToList();
                        foreach (var group in groups)
                        {
                            var toyopucHandler = plcTria.ToyopucHandler;
                            List<byte> data = new List<byte> { 0x00, 0x00 };
                            IndirectAddress indirectAddress = new IndirectAddress();
                            indirectAddress.Identifier = "D";
                            indirectAddress.Address = (uint)address;
                            ToyopucWrite(toyopucHandler, plcTria.ProgramCode, indirectAddress, data);
                        }
                    }
                }
                GolbalVariable.SignalLampDirectionBag.ForEach(x => { x.Status = 0; });
            });
            //所有信号灯状态重置
            foreach (var lamp in GolbalVariable.SignalLampDirectionBag)
            {
                lamp.Status = 0;
            }
            LogObj.Info("拉绳灯重置");
        }

        readonly object SignalLampControlObject = new object();
        /// <summary>
        /// 信号灯状态控制(PLC)
        /// </summary>
        /// <param name="itemAddress">PLC项地址</param>
        /// <param name="status">状态值：0熄灭；1点亮</param>
        public void SignalLampControl(string itemAddress, int status)
        {
            try
            {
                //先停止闪烁
                StopBlink(itemAddress);
            }
            catch (Exception ex)
            {
                LogObj.Error("信号灯停止闪烁失败！" + ex.Message);
            }
            SignalLampWrite(itemAddress, status);
        }

        /// <summary>
        /// 信号灯闪烁线程(PLC)
        /// </summary>
        /// <param name="itemAddress">PLC项地址</param>
        private void SignalLampBlink(string itemAddress)
        {
            while (true)
            {
                SignalLampWrite(itemAddress, 0);
                Thread.Sleep(500);
                SignalLampWrite(itemAddress, 1);
                Thread.Sleep(500);
            }
        }

        readonly object SignalLampBlinkObject = new object();
        /// <summary>
        /// 信号灯闪烁线程(PLC)
        /// </summary>
        /// <param name="itemAddress">PLC项地址</param>
        private void SignalLampBlink_New(string itemAddress)
        {
            while (true)
            {
                lock (SignalLampBlinkObject)
                {
                    var isBlink = SignalLampStateBag.Where(x => x.SignalLampAddress == itemAddress).FirstOrDefault().IsBlink;
                    if (isBlink)
                    {
                        SignalLampWrite(itemAddress, 0);
                        Thread.Sleep(600);
                        SignalLampWrite(itemAddress, 1);
                        Thread.Sleep(600);
                    }
                    else
                    {
                        Thread.Sleep(800);
                    }
                }
            }
        }

        readonly object SignalLampWriteObject = new object();
        /// <summary>
        /// 信号灯状态写入(PLC)
        /// </summary>
        /// <param name="itemAddress"></param>
        /// <param name="status"></param>
        private void SignalLampWrite(string itemAddress, int status)
        {
            lock (SignalLampWriteObject)
            {
                //根据item地址判断当前要操作的是那个bit(例:D130_A,转换结果为10)
                var bit = Convert.ToInt32(itemAddress.Split('_')[1], 16);
                //去掉第一位字符D，并把16进制字符串转10进制INT类型(例:D130_A,转换结果为304)
                var address = Convert.ToInt32(itemAddress.Split('_')[0].Substring(1, itemAddress.Split('_')[0].Length - 1), 16);
                //将数据更新至PLC
                foreach (var plcTria in GolbalVariable.PlcTriaList)
                {
                    if (plcTria.AccessMode == "readOnly")
                        continue;
                    var groups = plcTria.TriaGroups.Where(s => s.GroupId == itemAddress.Split('_')[0]).ToList();
                    foreach (var group in groups)
                    {
                        var toyopucHandler = plcTria.ToyopucHandler;
                        List<byte> data = new List<byte>();

                        var str = group.GroupStrs;
                        if (str == null)
                        {
                            str = "0000000000000000";
                        }
                        string newStr = "";
                        for (int i = 0; i < str.Length; i++)
                        {
                            if (bit == i)
                                newStr += status;
                            else
                                newStr += str[i];
                        }
                        group.GroupStrs = newStr;

                        data = Convert.ToInt16(PublicHelper.ReverseD(group.GroupStrs), 2).ToBytes().ToList();
                        IndirectAddress indirectAddress = new IndirectAddress();
                        indirectAddress.Identifier = "D";
                        indirectAddress.Address = (uint)address;
                        //LogObj.Debug(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + " 信号灯写入(" + itemAddress + ")" + str + "=>" + newStr);
                        waittingQueue.Enqueue(new WriteStruct { Toyopuc = toyopucHandler, Code = plcTria.ProgramCode, Address = indirectAddress, Val = data });
                        //ToyopucWrite(toyopucHandler, plcTria.ProgramCode, indirectAddress, data);
                    }
                }
            }
        }

        /// <summary>
        /// 信号灯控制
        /// </summary>
        /// <param name="toyopuc"></param>
        /// <param name="programCode"></param>
        /// <param name="indirectAddress"></param>
        /// <param name="data"></param>
        private void ToyopucWrite(IToyopuc toyopuc, ProgramCode programCode, IndirectAddress indirectAddress, List<byte> data)
        {
            try
            {
                //LogObj.Debug(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + " 信号灯写入(" + indirectAddress.Address + ")" + data[0]);
                var result = toyopuc.WriteExtString(programCode, indirectAddress, data.Take(2).ToList());
            }
            catch (Exception ex)
            {
                LogObj.Error("信号灯写值失败:" + ex.Message);
            }
        }

        private void Wrtite()
        {
            Task.Run(() =>
            {
                while (true)
                {
                    try
                    {
                        WriteStruct write;
                        if (!waittingQueue.Any() || !waittingQueue.TryDequeue(out write))
                        {
                            Thread.Sleep(20);
                            continue;
                        }
                        //LogObj.Debug(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + " 信号灯写入(" + write.Address.Address + ")" + write.Val.Take(2).ToList().ToArray().HexDisplay());
                        var result = write.Toyopuc.WriteExtString(write.Code, write.Address, write.Val.Take(2).ToList());
                    }
                    catch (Exception ex)
                    {
                        LogObj.Error("信号灯写入异常："+ex.Message);
                    }
                    //finally
                    //{
                    //    LogObj.Debug(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")+"队列数量：" +waittingQueue.Count);
                    //}
                }
            });

        }

        ConcurrentBag<SignalLampStateModel> SignalLampStateBag;
        private void BlinkThead()
        {
            SignalLampStateBag = new ConcurrentBag<SignalLampStateModel>();
            GolbalVariable.SignalLampMappingList.ForEach(f =>
            {
                Thread thread;
                SignalLampStateModel signalLampStateModel = new SignalLampStateModel
                {
                    SignalLampAddress = f.GreenOutputAddress,
                    Atreset = new AutoResetEvent(false),
                    IsBlink = false
                };
                SignalLampStateBag.Add(signalLampStateModel);
                GolbalVariable.SignalLampBlinkThreadDictionary.TryGetValue(f.GreenOutputAddress, out thread);
                if (thread == null)
                {
                    //新增闪灯线程
                    thread = new Thread(delegate ()
                    {
                        var greenOutputAddress = f.GreenOutputAddress;
                        while (true)
                        {
                            if (signalLampStateModel.IsBlink)
                            {
                                if (!signalLampStateModel.Atreset.WaitOne(700))
                                {
                                    SignalLampWrite(f.GreenOutputAddress, 1);
                                    if (!signalLampStateModel.Atreset.WaitOne(700))
                                    {
                                        SignalLampWrite(f.GreenOutputAddress, 0);
                                    }
                                    else
                                    {
                                        //SignalLampWrite(f.GreenOutputAddress, 1);
                                    }
                                }
                                else
                                {
                                    //SignalLampWrite(f.GreenOutputAddress, 1);
                                }
                            }
                            else
                            {
                                Thread.Sleep(200);
                            }
                        }
                    });
                    thread.Name = f.GreenOutputAddress;
                    thread.Start();
                    GolbalVariable.SignalLampBlinkThreadDictionary.TryAdd(f.GreenOutputAddress, thread);
                }
                Thread.Sleep(10);
            });
        }

        readonly object StopBlinkObject = new object();
        public void StopBlink(string itemAddress)
        {
            lock (StopBlinkObject)
            {
                var model = SignalLampStateBag.Where(x => x.SignalLampAddress == itemAddress).FirstOrDefault();
                if (model != null)
                {
                    model.IsBlink = false;
                    model.Atreset.Set();
                    LogObj.Debug(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + " 信号灯闪烁停止(" + itemAddress + ")");
                }
                else
                {
                    LogObj.Error("信号灯(" + itemAddress + ")不存在");
                }
            }
        }

        readonly object StartBlinkObject = new object();
        public void StartBlink(string itemAddress)
        {
            lock (StartBlinkObject)
            {
                var model = SignalLampStateBag.Where(x => x.SignalLampAddress == itemAddress).FirstOrDefault();
                if (model != null)
                {
                    var signalLamp = GolbalVariable.SignalLampMappingList.Where(x => x.GreenOutputAddress == model.SignalLampAddress).FirstOrDefault();
                    if (signalLamp != null)
                    {
                        //根据信号灯当前状态判断拉绳后的状态
                        var signalLamps = GolbalVariable.SignalLampDirectionBag.Where(x => x.SignalLampMappingID == signalLamp.ID).ToList();
                        signalLamps.ForEach(x => x.Status = 1);
                        model.IsBlink = true;
                        LogObj.Debug(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + " 信号灯闪烁开始(" + itemAddress + ")");
                    }
                }
                else
                {
                    LogObj.Error("信号灯(" + itemAddress + ")不存在");
                }
            }
        }

        public void StartBlinkAll()
        {
            SignalLampStateBag.ForEach(f =>
            {
                var signalLamp = GolbalVariable.SignalLampMappingList.Where(x => x.GreenOutputAddress == f.SignalLampAddress).FirstOrDefault();
                if(signalLamp != null)
                {
                    //根据信号灯当前状态判断拉绳后的状态
                    var signalLamps = GolbalVariable.SignalLampDirectionBag.Where(x => x.SignalLampMappingID == signalLamp.ID).ToList();
                    signalLamps.ForEach(x => x.Status = 1);
                    StartBlink(f.SignalLampAddress);
                    Thread.Sleep(10);
                }
            });
        }

        public void StopBlinkAll()
        {
            GolbalVariable.SignalLampMappingList.ForEach(f =>
            {
                StopBlink(f.GreenOutputAddress);
                Thread.Sleep(10);
            });
        }

        public void StartBlinkAndRedOpenAll()
        {
            GolbalVariable.SignalLampMappingList.ForEach(f =>
            {
                StartBlink(f.GreenOutputAddress);
                Thread.Sleep(10);
                SignalLampControl(f.RedOutputAddress, 1);
                Thread.Sleep(10);
            });
        }

        public void GreenOpenAll()
        {
            GolbalVariable.SignalLampMappingList.ForEach(f =>
            {
                SignalLampControl(f.GreenOutputAddress, 1);
                Thread.Sleep(10);
                SignalLampControl(f.RedOutputAddress, 0);
                Thread.Sleep(10);
            });
        }
    }
}
